<?php

namespace services\rbac;

use api\modules\v1\forms\rbac\RoleForm;
use common\components\Service;
use common\helpers\CommonHelper;
use common\helpers\DateHelper;
use common\helpers\RedisHelper;
use common\models\rbac\Role;
use common\models\rbac\RolePermission;
use services\api\AccessTokenService;
use services\log\LogMemberOpService;
use Yii;

/**
 * Class RoleService
 * @package services\rbac
 */
class RoleService extends Service
{
    /**
     * 角色列表
     * @param array $params
     * @param int $page
     * @param int $pageSize
     * @return array
     */
    public function getListPage(array $params = [], int $page = 0, int $pageSize = 0): array
    {
        $query = Role::find()->select(['*'])
            ->where([
                'status' => [Role::STATUS_INVALID, Role::STATUS_ENABLE],
            ]);

        $order = ['status' => SORT_DESC, 'sort' => SORT_ASC, 'id' => SORT_ASC];

        return $this->getListPageRes($query, $page, $pageSize, $order);
    }

    /**
     * 格式化菜单列表
     * @param array $data
     * @return array
     */
    public function getListPageFormat(array $data): array
    {
        $list = [];
        foreach ($data as $row) {
            $list[] = [
                'id' => $row['id'],
                'name' => $row['name'],
                'flag' => $row['flag'],
                'desc' => $row['desc'],
                'status_str' => Role::$statuss[$row['status']] ?? '',
//                'type_str' => Role::$types[$row['type']] ?? '',
                'created_at_str' => DateHelper::timestampToDate($row['created_at']),
                'updated_at_str' => DateHelper::timestampToDate($row['updated_at']),
            ];
        }
        return $list;
    }

    /**
     * 角色详情
     * @param int $id
     * @return array
     */
    public function getInfo(int $id): array
    {
        // 角色信息
        $role = Role::findOne($id);
        if (empty($role)) {
            return [];
        }

        return [
            'id' => $role->id,
            'name' => $role->name,
            'desc' => $role->desc,
            'status' => $role->status,
            'sort' => $role->sort,
        ];
    }

    /**
     * 根据角色Ids获取有效角色列表
     * @param array $ids
     * @return Role[]
     */
    public static function getEnableListByIds(?array $ids = null, $orIds = null): array
    {
        $query = Role::find()
            ->where([
                'status' => Role::STATUS_ENABLE
            ]);
        if (!is_null($ids)) {
            $query->andWhere(['id' => $ids]);
        }
        if ($orIds) {
            $query->orWhere([
                'id' => $orIds,
                'status' => [Role::STATUS_ENABLE, Role::STATUS_INVALID]
            ]);
        }
        return $query->orderBy(['sort' => SORT_ASC, 'id' => SORT_ASC])->all();
    }

    /**
     * 根据角色Ids获取角色列表【禁用 + 正常】
     * @param array $params
     * @return Role[]
     */
    public static function getNormalListByIds(array $ids = []): array
    {
        $query = Role::find()
            ->select(['*'])
            ->where([
                'status' => [Role::STATUS_INVALID, Role::STATUS_ENABLE],
            ]);
        if ($ids) {
            $query->andWhere(['id' => $ids]);
        }
        return $query->orderBy(['sort' => SORT_ASC, 'id' => SORT_ASC])->all();
    }

    /**
     * 根据Ids获取角色列表【禁用 + 正常】
     * @param array $roleIds
     * @return Role[]
     */
    public static function getNormalCacheListByIds(array $roleIds): array
    {
        $data = [];
        foreach ($roleIds as $roleId) {
            $role = RedisHelper::getRole($roleId);
            if (empty($role) || $role->status == Role::STATUS_DELETE) {
                continue;
            }
            $data[] = $role;
        }
        return $data;
    }

    /**
     * 获取下拉列表筛选项
     * @return array
     */
    public static function getListCondition(): array
    {
        return CommonHelper::getListCondition(self::getNormalListByIds(), ['value_column' => 'id', 'label_column' => 'name']);
    }

    /**
     * 详情绑定项目列表
     * @param int|array|null $ids
     * @param int|array|null $orId
     * @return array
     */
    public static function getEditCondition($ids, $orId): array
    {
        return CommonHelper::getListCondition(self::getEnableListByIds($ids, $orId), ['value_column' => 'id', 'label_column' => 'name']);
    }

    /**
     * 编辑角色
     * @param Role $role
     * @param RoleForm $model
     * @return Role
     * @throws \Exception
     */
    public static function editModel(Role $role, RoleForm $model): Role
    {
        $role->name = $model->name;
        $role->desc = $model->desc;
//        $role->type = $model->type;
        $role->status = $model->status;
        $role->saveAndCheckResult();

        return $role;
    }

    /**
     * 新增角色
     * @param RoleForm $model
     * @return array
     */
    public function create(RoleForm $model): array
    {
        try {
            $transaction = Yii::$app->db->beginTransaction();

            // 1.新增角色
            $role = new Role();
            $role = self::editModel($role, $model);

            // 2.日志
            LogMemberOpService::createRoleLog($model, $role);

            $transaction->commit();
            return ['id' => $role->id];
        } catch (\Exception $e) {
            $transaction->rollBack();
            throw $e;
        }
    }

    /**
     * 编辑角色
     * @param RoleForm $model
     */
    public function edit(RoleForm $model): array
    {
        try {
            $transaction = Yii::$app->db->beginTransaction();

            // 1.新增角色
            $oldRole = new Role();
            $oldRole->setAttributes($model->getRole()->getAttributes());
            $role = self::editModel($model->getRole(), $model);

            // 2.日志
            LogMemberOpService::createRoleLog($model, $role, $oldRole);

            // 3.更新缓存
            RedisHelper::setRole($role);

            $transaction->commit();
            return ['id' => $role->id];
        } catch (\Exception $e) {
            $transaction->rollBack();
            throw $e;
        }
    }

    /**
     * 编辑角色权限
     * @param RoleForm $model
     */
    public function editPermission(RoleForm $model): array
    {
        try {
            $transaction = Yii::$app->db->beginTransaction();

            // 1-1.删除角色权限
            RolePermissionService::deleteRoleActionPermission($model->id, $model->getDeleteActionIds());
            RolePermissionService::deleteRoleMenuPermission($model->id, $model->getDeleteMenuIds());
            // 1-2.新增角色权限
            $data = [];
            foreach ($model->getAddActionIds() as $id) {
                $data[] = [
                    $model->id,
                    $id,
                    RolePermission::PERMISSION_TYPE_ACTION,
                    Yii::$app->user->identity->member_id,
                    time(),
                    time(),
                ];
            }
            foreach ($model->getAddMenuIds() as $id) {
                $data[] = [
                    $model->id,
                    $id,
                    RolePermission::PERMISSION_TYPE_MENU,
                    Yii::$app->user->identity->member_id,
                    time(),
                    time(),
                ];
            }
            $data && Yii::$app->db->createCommand()->batchInsert(RolePermission::tableName(), [
                'role_id', 'permission_id', 'permission_type', 'operation_id', 'created_at', 'updated_at'
            ], $data)->execute();

            // 2.日志
            if (LogMemberOpService::createRoleLog($model, $model->getRole())) {
                // 3.绑定角色人员强制退出登录
                MemberRoleService::clearRoleMemberToken($model->id);
            }

            $transaction->commit();
            return ['id' => $model->id];
        } catch (\Exception $e) {
            $transaction->rollBack();
            throw $e;
        }
    }

    /**
     * 删除角色
     * @param RoleForm $model
     */
    public function delete(RoleForm $model): array
    {
        try {
            $transaction = Yii::$app->db->beginTransaction();

            // 1.更新动作
            $role = $model->getRole();
            $role->status = Role::STATUS_DELETE;
            $role->saveAndCheckResult();
            // 2.清空人员绑定角色
            $memberIds = MemberRoleService::deleteUserRole($role->id);
            // 3.清空绑定角色人员token
            AccessTokenService::clearMemeberToken($memberIds);
            // 4.日志
            LogMemberOpService::createRoleLog($model, $role);
            // 5.更新缓存
            RedisHelper::delRole($role->id);

            $transaction->commit();
            return ['id' => $role->id];
        } catch (\Exception $e) {
            $transaction->rollBack();
            throw $e;
        }
    }
}
